// #define print(...)
#define map_t unordered_map
struct SearchInfo{
    // 搜索过的线路
    list<int> ln;
    // <line, transfer_times> 到达每条线所需换乘次数
    map_t<int, int> jmp;
};
class Solution {
    SearchInfo infos[2];
    // <line, points> 各条线上的站点
    std::vector<std::set<int>> l2p;
    // <point, lines> 各个站点可换乘的线路
    map_t<int, std::set<int>> p2l;
public:
    int numBusesToDestination(vector<vector<int>>& routes, int source, int target) {
        print(routes, "\n")
        if(source == target) return 0;
        // init map 
        l2p.reserve(routes.size());
        l2p.resize(routes.size());
        for(int l=0; l<routes.size(); l++){
            auto &pts = routes[l];
            for(auto &p : pts)
                p2l[p].insert(l);
            l2p[l].insert(pts.begin(), pts.end());
        }
        auto & sl = p2l[source];
        for(auto &l : p2l[target]){
            if(sl.count(l)) return 1;
        }
        // terminal lines
        int peers[] = {source, target};
        for(int i=0; i<2; i++){ // src, dst
            auto &lns = p2l[peers[i]];
            infos[i].ln.insert(infos[i].ln.end(), lns.begin(), lns.end());
            for(auto &l : lns) infos[i].jmp[l] = 1;
        }
        // bfs
        auto forward = infos, back = infos+1;
        while(forward->ln.size() && back->ln.size()){
            if(forward->ln.size() > back->ln.size())
                swap(forward, back);
            print("q[", back-infos, "] = ", back->ln, "\n")
            int jump = bfs(*forward, back->jmp);
            if( jump > 0 ) return jump;
        }
        return -1;
    }
    int bfs(SearchInfo & forward, map_t<int,int> & backJmp){
        print("q[", &forward-infos, "] = ", forward.ln, "\n")
        int ln = forward.ln.front(); forward.ln.pop_front();
        int jmp = forward.jmp[ln];
        print("m[", &forward-infos, "] = ", forward.jmp,"\n")
        print("m[",infos-&forward+1,"] = ", backJmp,"\n")
        for(auto &p : l2p[ln]){
            print(p, ":->", p2l[p], "\n")
            for(auto &l : p2l[p]){
                if(l == ln || forward.jmp.count(l)) continue;
                if(backJmp.count(l)) return jmp + backJmp[l];
                forward.ln.push_back(l);
                forward.jmp[l] = jmp + 1;
            }
        }
        return -1;
    }
};